package gate

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var secretKey string

type CustomClaims struct {
	UserID string `json:"userId"`
	Role   string `json:"role"`
	jwt.RegisteredClaims
}

func InitSecretKey(key string) {
	if key == "" {
		log.Fatal("JWT密钥不能为空")
	}
	if len(key) < 32 {
		log.Fatal("JWT密钥长度至少32位")
	}
	secretKey = key
}

func generateJWT(userID, role string) (string, time.Time, error) {
	expiration := time.Now().Add(24 * time.Hour)

	// 创建自定义声明
	claims := CustomClaims{
		UserID: userID,
		Role:   role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiration),
			Issuer:    "my-auth-service",
		},
	}

	// 创建令牌对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名令牌
	tokenString, err := token.SignedString([]byte(secretKey))
	if err != nil {
		return "", time.Time{}, err
	}

	return tokenString, expiration, nil
}

func AuthMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tokenString := ""
		// 尝试从 Cookie 获取 token
		if cookie, err := r.Cookie("token"); err == nil {
			tokenString = cookie.Value
		}

		// 尝试从 Authorization 头获取 token
		if tokenString == "" {
			authHeader := r.Header.Get("Authorization")
			if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") {
				tokenString = strings.TrimPrefix(authHeader, "Bearer ")
			}
		}

		if tokenString == "" {
			WriteErrorResponse(w, r, http.StatusUnauthorized, "Authorization token required")
			return
		}

		token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
			}
			return []byte(secretKey), nil
		})

		if err != nil {
			switch {
			case errors.Is(err, jwt.ErrTokenExpired):
				WriteErrorResponse(w, r, http.StatusUnauthorized, "Token expired")
			default:
				WriteErrorResponse(w, r, http.StatusUnauthorized, "Invalid token")
			}
			log.Printf("Token verification failed: %v", err)
			return
		}

		// 类型断言获取声明
		claims, ok := token.Claims.(*CustomClaims)
		if !ok || !token.Valid {
			WriteErrorResponse(w, r, http.StatusUnauthorized, "Invalid token claims")
			return
		}

		// 令牌验证成功，将声明添加到请求上下文
		ctx := context.WithValue(r.Context(), "userClaims", claims)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}
